package com.atzly.community.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 *  前缀树过滤敏感字段
 * @author zlysimida
 * @date 2021/8/27 - 21:31
 */
@Component
@Slf4j
public final class SensitiveFilter {

    // 替换敏感字段
    private final static String REPLACEMENT = "***";

    // 根节点
    private TireNode rootNode = new TireNode();

    private SensitiveFilter() {}

    // 初始化前缀树,在JVM初始化类的构造器后执行
    @PostConstruct
    public void init(){
        try(
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                BufferedReader bis = new BufferedReader(new InputStreamReader(is));
        ) {
            String keyWord;
            while ((keyWord = bis.readLine()) != null){
                // 添加到前缀树
                this.addKeyWord(keyWord);
            }
        } catch (IOException e) {
            log.error("读取敏感文件失败!"+e.getMessage());
        }

    }


    // 添加敏感字到前缀树中
    private void addKeyWord(String keyWord) {
        TireNode tempNode = rootNode;
        for (int i = 0; i < keyWord.length(); i++){
            Character c = keyWord.charAt(i);

            // 检查树中是否存在该节点
            TireNode childNode = tempNode.getChildNode(c);
            if(childNode == null) {
                childNode = new TireNode();
                tempNode.setChildNode(c,childNode);
            }
            tempNode = childNode;

            // 设置结束标志
            if(i == keyWord.length() - 1){
                tempNode.setFlag(true);
            }
        }
    }

    /**
     *  过滤敏感词
     * @param text
     * @return 过滤后的文本
     */
    public String filter(String text){
        if(StringUtils.isBlank(text)){
            return null;
        }
        // 指针1
        TireNode tempNode = rootNode;
        // 指针2
        int begin = 0;
        // 指针3
        int position = 0;
        // 返回的结果
        StringBuilder sb = new StringBuilder();

        while (position < text.length()){
            Character c = text.charAt(position);

            // 跳过特殊符号
            if(isSymbol(c)){
                if(tempNode == rootNode){
                    sb.append(c);
                    begin++;
                }
                // 如果符号在开头还是中间指针3向下走
                position++;
                continue;
            }

            // 检查下级节点
            tempNode = tempNode.getChildNode(c);
            if(tempNode == null){
                // 以begin开头的字符串不是敏感词
                sb.append(text.charAt(begin));
                position = ++begin;
                tempNode = rootNode;
            }else if(tempNode.isFlag()){
                // 发现敏感词,将begin~position字符串替换掉
                sb.append(REPLACEMENT);
                begin = ++position;
                tempNode = rootNode;
            }else{
                position++;
            }

        }

        // postion跑的比begin快,将最后一批字符计入结果
        sb.append(text.substring(begin));
        return sb.toString();

    }

    // 判断是否为符号
    private boolean isSymbol(Character c){
        // 0x2E80~0x9FFF 是东亚文字范围
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }




    // 定义字典树的数据结构
    private class TireNode{

        // 标志位
        private boolean flag = false;

        // 孩子节点
        private Map<Character,TireNode> childNodes = new HashMap<>();

        private boolean isFlag() {
            return flag;
        }

        private void setFlag(boolean flag) {
            this.flag = flag;
        }

        private void setChildNode(Character c, TireNode node){
                childNodes.put(c,node);
        }

        private TireNode getChildNode(Character c){
            return this.childNodes.get(c);
        }
    }
}
